Skip to content

Fetch cheaply: a worker learns what a fetch costs, and a dispatch says what it is doing - #443

Merged
m2ux merged 8 commits into
workflow/delivery-cost-startup-ceremonyfrom
workflow/delivery-cost-fetch-guidance
Aug 7, 2026
Merged

Fetch cheaply: a worker learns what a fetch costs, and a dispatch says what it is doing#443
m2ux merged 8 commits into
workflow/delivery-cost-startup-ceremonyfrom
workflow/delivery-cost-fetch-guidance

Conversation

@m2ux

@m2ux m2ux commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Two things agents were left to work out for themselves. What a fetch costs — so a worker fetched the
same technique twice inside 46 seconds, and probed resource ids under alternate spellings when the
right one was in the response it was holding. And what a dispatch is doing — so one ran fifteen
minutes with nothing for the user to read, and the checkpoint it was heading for arrived unannounced
while they sat waiting on it.

Work item W3, the corpus half of W8, and the running-dispatch signal that extends W2, all of the
delivery-cost epic #404. Stacked on #439.

Fetch guidance

Four things a worker now reads, all of them in workflow-engine's container rules where the fetch
contract already lives:

  • Ids come from the delivery. The resources map keys, resource_refs, and the refs in the
    operation bodies the response carried, each already qualified. A ref that will not resolve is a
    definition defect to report — not a spelling to search for. An id guessed under another workflow
    prefix costs a round trip and returns an error, and the one that would have worked was in the
    response.
  • A fetch hands over the whole composed body. With the measured range from one real run: lazy
    technique fetches ran 5,242 to 15,126 characters apiece, lazy resource fetches 1,426 to 14,980.
  • A repeat under the same agent_id comes back as a marker, because the ledger records that this
    context received those bytes. So a repeat costs the round trip rather than the body, and the marker
    is the expected answer rather than an error. This is behaviour Send once: a delivery stops repeating what it has already handed over, and says where the context stands #441 adds; the guidance describes it
    rather than promising it.
  • A shared block inside one activity response may be a marker whose bytes an earlier
    step_techniques entry of that same response carries in full — read it from there. Also Send once: a delivery stops repeating what it has already handed over, and says where the context stands #441.

progressive-step-technique-load now says plainly that an inlined step is read from the bundle,
because re-fetching it pays the round trip for content the response already delivered.

Where the batch standing is read

#441 puts the standing in the response text as a leading batch: block, because _meta was not where
a worker reliably read it — on the 5 August run no context anywhere took a second activity and nothing
was refused either, because no continuation was ever attempted. The three places in the corpus that
name the field now name the block: the worker's verify-dispatch phase, the rule that governs where a
batch ends, and finalize-activity's input that carries the answer into the envelope.

A dispatch says what it is doing while it runs

The orchestrator announces each dispatch before it spawns: what is running, the gate the user's answer
is next needed at, and the elapsed figure of the last comparable dispatch where the session record has
one. The rule behind it carries what the phase cannot: no minute of a run is silent, so the waits the
orchestrator itself imposes between dispatches — a commit cycle, a reconciliation, a retry — are named
as they happen, and where a dispatch is one of a run of activities under one worker, which of the run
it is belongs in the announcement.

W2 puts the same measurement on the log, facing the operator. This is the half that faces the person
waiting.

Scope of change

Five definition files, all in the meta workflow: workflow-engine/TECHNIQUE.md (one rule extended,
one added), activity-worker.md, finalize-activity.md, dispatch-activity.md (one protocol phase,
one rule), and the workflow version. No activity YAML, no schema, no server change.

Verification

All 24 guards pass against this corpus.

Dependencies

The fetch guidance and the batch-standing location describe server behaviour that lands with #440 and
#441. Merging this first would document behaviour the server does not have yet.

Non-goals

  • Where a lazy fetch's cost comes from. The resolve work behind it is Resolve once: a delivery reads each technique one time, and says what it cost #440's, and this guidance quotes
    what a fetch delivers rather than how the server builds it.
  • The eager bundle's budget behaviour, unchanged.
  • Retiring any fetch. The point is that a worker asks for what a step needs and reuses what it already
    has, not that it asks less.

Investigation detail

engineering/artifacts/planning/2026-08-06-startup-cost-on-real-runs
— the repeat-fetch tables and the per-delivery figures quoted above.

Fetch guidance: resource ids come from the delivery's own maps and refs, so an
unresolvable one is a defect to report rather than a spelling to search for; a
fetch hands over the whole composed body, with the measured range from one real
run; a repeat under the same agent_id comes back as a marker, so it costs the
round trip rather than the body; and a shared block inside one activity response
may be a marker whose bytes an earlier entry of that response carries.

The batch standing is read from the batch: block leading each get_activity
response, which the three places that name it now say.

A dispatch announces itself before it spawns — what is running, the gate the
user's answer is next needed at, and how long a comparable dispatch took — and no
minute of a run is silent, including the waits the orchestrator imposes between
dispatches.
m2ux added 7 commits August 6, 2026 13:30
…eeded for

The announcement is a standing duty across the whole dispatch loop, not a work
outcome at one position in it, so it lives once under Rules and instructs the
orchestrator directly. That also removes its citation of a protocol phase by
ordinal, which would have addressed the wrong work after any renumber.

An opt-in is what get_activity needs to collapse its bundle. A repeat technique
or resource fetch to a named context collapses without one, so the rule that
describes the ledger says which call each ground governs, and the fetch rule
points at the one that says how to avoid the second ask at all.
The rule restated two contracts that already have homes: when a marker comes
back, which the ledger-scoping rule owns, and what a marker inside one response
stands for, which that response's own notes own — the stance its sibling
progressive-step-technique-load already states, that the response notes govern
rather than policy re-derived in prose.

What is left is what only this rule holds: what a fetch costs, measured, and the
instruction to ask for what a step needs.
The rule is on a container, so it reaches every operation inside it and every
worker through the activity bundle. A range from one historical run is not
something a reader can act on differently, and it dates — which makes it exactly
the fan-out the batch benchmark's warn-only line counts: characters delivered
with no observable behaviour behind them.

What a fetch costs is stated in the terms a reader acts on. The measured range
lives in the epic's planning record, which is its home.
Two things were wrong once a repeat stopped collapsing on the session's own
identity. The exception is that identity, reached by passing it as much as by
omitting agent_id and falling back to it — not the omission. And a solo walk does
collapse a repeat: it declares reference delivery, which is the ground the
exception leaves open, so saying nothing collapses for it was the reverse of the
truth.
@m2ux
m2ux merged commit aa8f779 into workflow/delivery-cost-startup-ceremony Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant